package com.weilele.mvvm.utils

/**
 *责任链模式，
 * 比如员工向公司请假，组长审批，主管审批，老板审批
 * okHttp的拦截器就是责任链模式
 */

/**
 * 需要被处理的对象
 */
class ProductObj<INPUT/*输入对象（给处理者查看）*/, OUTPUT/*产出对象（有处理者产出）*/> {
    private val workers: MutableList<IWorker<INPUT, OUTPUT>> = mutableListOf()

    /**
     * 获取注册的对象
     */
    fun getWorks(): List<IWorker<INPUT, OUTPUT>> = workers

    /**
     * 添加处理者
     */
    fun addWorker(worker: IWorker<INPUT, OUTPUT>) {
        if (!workers.contains(worker)) {
            workers.add(worker)
        }
    }

    /**
     * 移除处理者
     */
    fun removeWorker(worker: IWorker<INPUT, OUTPUT>) {
        workers.add(worker)
    }

    /**
     * 清空处理者
     */
    fun clearWorkers() {
        workers.clear()
    }

    /**
     * 开始给处理者处理
     */
    fun startAwait(input: INPUT, defaultOutput: OUTPUT? = null): OUTPUT? {
        return RealWorkerChain(input, defaultOutput, 0, workers)
            .getNextOutput(input, defaultOutput)
    }

    /**
     * 开始给处理者处理
     */
    fun startAsync(input: INPUT, defaultOutput: OUTPUT? = null, listener: (OUTPUT?) -> Unit) {
        RealWorkerChain(input, defaultOutput, 0, workers)
            .getNextOutput(input, defaultOutput, listener)
    }
}

/**
 * 处理者
 */
interface IWorker<INPUT, OUTPUT> {

    /**
     * 处理链，信息的传递
     * 用于接受输入信息，返回输出信息
     */
    interface Chain<INPUT, OUTPUT> {
        /**
         * 当前处理对象，在集合的位置
         */
        fun getIndex(): Int

        /**
         * 获取输出信息
         */
        fun getInput(): INPUT

        /**
         *获取上一个的输入信息
         */
        fun getOutput(): OUTPUT?

        /**
         * 交给下一个处理者
         * 特别注意调用时机
         * 一般放在最后一行返回
         * 如果不调用这个方法，表示处理完成，不再给下一个处理
         */
        fun getNextOutput(input: INPUT = getInput(), output: OUTPUT? = getOutput()): OUTPUT?

        fun getNextOutput(
            input: INPUT = getInput(),
            output: OUTPUT? = getOutput(),
            listener: (OUTPUT?) -> Unit
        )
    }

    /**
     * 处理流程
     */
    fun onWork(chain: Chain<INPUT, OUTPUT>): OUTPUT?

    fun onWork(chain: Chain<INPUT, OUTPUT>, listener: (OUTPUT?) -> Unit)
}

/**
 * 处理链的逻辑处理
 */
class RealWorkerChain<INPUT, OUTPUT>(
    private val input: INPUT,
    private val output: OUTPUT?,
    private val index: Int,
    private val workers: MutableList<IWorker<INPUT, OUTPUT>>
) : IWorker.Chain<INPUT, OUTPUT> {

    override fun getIndex(): Int = index

    override fun getInput() = input

    override fun getOutput() = output

    override fun getNextOutput(
        input: INPUT,
        output: OUTPUT?
    ): OUTPUT? {
        //如果没有下一级审批，返回上一级的审批结果
        return if (index >= workers.count()) {
            output
        } else {
            val next =
                RealWorkerChain(input, output, index + 1, workers)
            val worker = workers[index]
            worker.onWork(next)
        }
    }

    override fun getNextOutput(
        input: INPUT,
        output: OUTPUT?,
        listener: (OUTPUT?) -> Unit
    ) {
        //如果没有下一级审批，返回上一级的审批结果
        if (index >= workers.count()) {
            listener.invoke(output)
        } else {
            val next =
                RealWorkerChain(input, output, index + 1, workers)
            val worker = workers[index]
            worker.onWork(next, listener)
        }
    }
}

fun main(args: Array<String>) {
    val test = ProductObj<String, Int>()
    test.addWorker(object : IWorker<String, Int> {
        override fun onWork(chain: IWorker.Chain<String, Int>): Int? {
//            val input = chain.getInput()
//            val lastOutput = chain.getOutput()
//            chain.getNextOutput()
//            return chain.getNextOutput(input, lastOutput)
            return chain.getNextOutput()
        }

        override fun onWork(chain: IWorker.Chain<String, Int>, listener: (Int?) -> Unit) {
            val input = chain.getInput()
            val lastOutput = chain.getOutput()
            listener.invoke(chain.getNextOutput(input, lastOutput))
        }
    })
    test.addWorker(object : IWorker<String, Int> {
        override fun onWork(chain: IWorker.Chain<String, Int>): Int? {
            val input = chain.getInput()
            val lastOutput = chain.getOutput()
            return chain.getNextOutput(input, lastOutput)
        }

        override fun onWork(chain: IWorker.Chain<String, Int>, listener: (Int?) -> Unit) {
            val input = chain.getInput()
            val lastOutput = chain.getOutput()
            chain.getNextOutput(input, lastOutput, listener)
        }
    })
    test.addWorker(object : IWorker<String, Int> {
        override fun onWork(chain: IWorker.Chain<String, Int>): Int? {
            val input = chain.getInput()
            val lastOutput = chain.getOutput()
            return chain.getNextOutput(input, lastOutput)
        }

        override fun onWork(chain: IWorker.Chain<String, Int>, listener: (Int?) -> Unit) {
            val input = chain.getInput()
            val lastOutput = chain.getOutput()
            chain.getNextOutput(input, lastOutput, listener)
        }
    })
    val v1 = test.startAwait("1", 555)
    test.startAsync("1", 666) {

    }

}
